#!/usr/bin/perl -w

use strict;
use Device::SerialPort;
use Net::OpenSoundControl::Server;
use HTTP::Server::Simple::Dispatched qw(static);
#use HTTP::Daemon;
#use HTTP::Status;
use threads;
use Data::Dumper qw(Dumper);

my $DIAS_NUM = $ARGV[0] || 20;
my $DIAS_ON_TIME = 10;
my $DIAS_STATE = 1;
my $LAMP_STATE = 0;

my $WITH_SERIAL_PORT = 1;

my $CMD_SYNC = 3;
my $CMD_FORWARD = 6;
my $CMD_BACKWARD = 2;
my $CMD_FADE_IN = 1;
my $CMD_FADE_OUT = 7;

my $my_id = 0;

my $port_name = '/dev/ttyUSB0';
my $port_obj;

my $i;
my ($count, $string);

if ($WITH_SERIAL_PORT) {
	$port_obj = new Device::SerialPort($port_name) || die "Can't open $port_name: $!\n";
	$port_obj->baudrate(9600);
	$port_obj->databits(8);
	$port_obj->stopbits(1);
	$port_obj->parity("none");
}

sub lamp {
	my ($id, $value) = @_;
 	if (sprintf("%.0f", $value) > 0.2) {
 		# on
 		if ($LAMP_STATE == 0) {
			if ($WITH_SERIAL_PORT) {
	 			$port_obj->write($CMD_FADE_IN | ($id << 5));
	 		}
			warn "sent CMD_FADE_IN\n";
			warn "dias $DIAS_STATE on\n\n";
	 		$LAMP_STATE = 1;
		}
 	}
 	else {
 		# off
 		if ($LAMP_STATE > 0) {
			if ($WITH_SERIAL_PORT) {
				$port_obj->write($CMD_FADE_OUT | ($id << 5));
			}
			warn "sent CMD_FADE_OUT\n";
			warn "dias $DIAS_STATE off\n\n";
			$LAMP_STATE = 0;
	 	}
 	}
}

sub forward {
	my $id = shift;
	if ($DIAS_STATE == $DIAS_NUM) {
		if ($WITH_SERIAL_PORT) {
	 		$port_obj->write($CMD_FORWARD | ($id << 5));
	 	}
		warn "sent CMD_FORWARD\n";
 		$DIAS_STATE = 1;
		warn "dias change to $DIAS_STATE\n\n";
 	}
 	else {
		if ($WITH_SERIAL_PORT) {
	 		$port_obj->write($CMD_FORWARD | ($id << 5));
	 	}
		warn "sent CMD_FORWARD\n";
 		$DIAS_STATE++;
		warn "dias change to $DIAS_STATE\n\n";
 	}
}

sub backward {
	my $id = shift;
	if ($DIAS_STATE == 1) {
		if ($WITH_SERIAL_PORT) {
	 		$port_obj->write($CMD_BACKWARD | ($id << 5));
	 	}
		warn "sent CMD_BACKWARD\n";
 		$DIAS_STATE = $DIAS_NUM;
		warn "dias change to $DIAS_STATE\n\n";
 	}
 	else {
		if ($WITH_SERIAL_PORT) {
	 		$port_obj->write($CMD_BACKWARD | ($id << 5));
	 	}
		warn "sent CMD_BACKWARD\n";
 		$DIAS_STATE--;
		warn "dias change to $DIAS_STATE\n\n";
 	}
}

sub sync {
	my $id = shift;
	if ($WITH_SERIAL_PORT) {
		$port_obj->write($CMD_FADE_OUT | ($id << 5));
		$port_obj->write($CMD_SYNC | ($id << 5));
	}
	warn "sent CMD_FADE_OUT\n";
	warn "sent CMD_SYNC\n";
	# resetting state here...
	$DIAS_STATE = 1;
	$LAMP_STATE = 0;
	warn "dias reset to $DIAS_STATE and lamp off\n\n";
}

sub dumpmsg {
	my $i;
	my ($sender, $message) = @_;
	my ($scope, $type, $value) = (($message->[0]), ($message->[1]), ($message->[2]));
	if ($scope =~ /lamp/i) {
		lamp($my_id, $value);
 	}
 	elsif ($scope =~ /forward/i) {
		if (sprintf("%.0f", $value) > 0.2) {
			forward($my_id);
		}
 	}
 	elsif ($scope =~ /backward/i) {
	 	if (sprintf("%.0f", $value) > 0.2) {
			backward($my_id);
 		}
 	}
 	elsif ($scope =~ /sync/i) {
		sync($my_id);
	}
}

my $http_server = HTTP::Server::Simple::Dispatched->new(
	port     => 8080,
	debug    => 1,
	dispatch => [
		qr{^/.*lamp.*[1-9]/} => sub {
			my ($response, $request, $context) = @_;
			lamp($my_id, 1);
			
			$response->content_type('text/html');
			open(HANDLE, $ENV{"HOME"} . '/kodak_timer/osc_to_serial_server.html') || die $!;
			my $html;
			{ undef $/; $html = <HANDLE>; }
			close(HANDLE);
			$html =~ s/DIAS_STATE/$DIAS_STATE/;
			$response->content($html);
			return 1;
		},
		qr{^/.*lamp.*[0]/} => sub {
			my ($response, $request, $context) = @_;
			lamp($my_id, 0);
			
			$response->content_type('text/html');
			open(HANDLE, $ENV{"HOME"} . '/kodak_timer/osc_to_serial_server.html') || die $!;
			my $html;
			{ undef $/; $html = <HANDLE>; }
			close(HANDLE);
			$html =~ s/DIAS_STATE/$DIAS_STATE/;
			$response->content($html);
			return 1;
		},
		qr{^/.*forward/} => sub {
			my ($response, $request, $context) = @_;
			forward($my_id);
			
			$response->content_type('text/html');
			open(HANDLE, $ENV{"HOME"} . '/kodak_timer/osc_to_serial_server.html') || die $!;
			my $html;
			{ undef $/; $html = <HANDLE>; }
			close(HANDLE);
			$html =~ s/DIAS_STATE/$DIAS_STATE/;
			$response->content($html);
			return 1;
		},
		qr{^/.*backward/} => sub {
			my ($response, $request, $context) = @_;
			backward($my_id);
			
			$response->content_type('text/html');
			open(HANDLE, $ENV{"HOME"} . '/kodak_timer/osc_to_serial_server.html') || die $!;
			my $html;
			{ undef $/; $html = <HANDLE>; }
			close(HANDLE);
			$html =~ s/DIAS_STATE/$DIAS_STATE/;
			$response->content($html);
			return 1;
		},
		qr{^/sync/} => sub {
			my ($response, $request, $context) = @_;
			sync($my_id);
			
			$response->content_type('text/html');
			open(HANDLE, $ENV{"HOME"} . '/kodak_timer/osc_to_serial_server.html') || die $!;
			my $html;
			{ undef $/; $html = <HANDLE>; }
			close(HANDLE);
			$html =~ s/DIAS_STATE/$DIAS_STATE/;
			$response->content($html);
			return 1;
		},
		qr{^/} => sub {
			my ($response, $request, $context) = @_;
			
			$response->content_type('text/html');
			open(HANDLE, $ENV{"HOME"} . '/kodak_timer/osc_to_serial_server.html') || die $!;
			my $html;
			{ undef $/; $html = <HANDLE>; }
			close(HANDLE);
			$html =~ s/DIAS_STATE/$DIAS_STATE/;
			$response->content($html);
			return 1;
		}
	]
);

sub http_daemon() {
	$http_server->run();
}

my $thr = threads->new(\&http_daemon);
		
warn "http daemon started";

my $server = Net::OpenSoundControl::Server->new(Port => 1234, Handler => \&dumpmsg) || die "Could not start server: $@\n";
warn "osc server started";
$server->readloop();

END {
	if ($WITH_SERIAL_PORT) {
		$port_obj->close || warn "close failed";
	}
}

1;
